#include "../include/kasm.h"
#include "../include/defs.h"
#include "../include/pantalla.h"
#include "../include/teclado.h"
#include "../include/kernel.h"
#include "../include/mouse.h"
#include "../include/stdio.h"

int get_gdtr_limit(void);
int get_gdtr_base(void);

/*
 * Inicializa un descriptor de la IDT. Recibe puntero a elemento de la IDT, selector a cargar,
 * puntero a rutina de atencion, derechos de acceso al segmento y cero
 */
void setup_IDT_entry (DESCR_INT *item, byte selector, dword offset, byte access,
			 byte cero) {
  item->selector = selector;
  item->offset_l = offset & 0xFFFF;
  item->offset_h = offset >> 16;
  item->access = access;
  item->cero = cero;
}

/*
 * Carga los descriptores de la IDT necesarios y habilita en los pic las interrupciones que se van a usar
 */
void cargaIDT()
{
	IDTR idtr;

	setup_IDT_entry (&idt[0x08], 0x08, (dword)&_int_08_hand, ACS_INT, 0); /* CARGA DE IDT CON LA RUTINA DE ATENCION DE IRQ0  - TIMERTICK */
	setup_IDT_entry (&idt[0x09], 0x08, (dword)&_int_09_hand, ACS_INT, 0); /* CARGA DE IDT CON LA RUTINA DE ATENCION DE IRQ1  - TECLADO */
	setup_IDT_entry (&idt[0x74], 0x08, (dword)&_int_74_hand, ACS_INT, 0); /* CARGA DE IDT CON LA RUTINA DE ATENCION DE IRQ12 - MOUSE */

	idtr.base = 0;
	idtr.base +=(dword) &idt;
	idtr.limit = sizeof(idt)-1;
	_lidt (&idtr);

	/* Habilito interrupcion del teclado, timertick, mouse y la cascada*/
    _mascaraPIC1(0xF8); // 1111 1000
    _mascaraPIC2(0xEF); // 1110 1111
}

//Setea el segmento
void gdt_set_gate( DESCR_SEG * item, unsigned long base, unsigned long limit,unsigned char access, unsigned char attr)
{
    item->base_low = (base & 0xFFFF);
    item->base_middle = (base >> 16) & 0xFF;
    item->base_high = (base >> 24) & 0xFF;

    item->limit_low = (limit & 0xFFFF);
    item->attribs = ((limit >> 16) & 0x0F);

    item->attribs |= (attr & 0xF0);
    item->access = access;
}


void cargaGDT()
{
	gdt_set_gate(&gdt[0x01], 0, 0xFFFFF, ACS_CODE, 0xC0);
	gdt_set_gate(&gdt[0x02], 0, 0xFFFFF, ACS_STACK, 0xC0);

	GDTR gdtr;
	gdtr.base = 0;
	gdtr.base +=(dword) &gdt;
	gdtr.limit = sizeof(gdt)-1;

	_lgdt(&gdtr);
}

void printGDT(){
	int i = 0;
	for(i=0; i<6; i++)
	{
		printf("Base High: %d", gdt[i].base_high);
		printf(" Base middle: %d", gdt[i].base_middle);
		printf(" Base low: %d\n", gdt[i].base_low);
	}
}

int kmain()
{
    // Deshabilito todas las interrupciones en los dos pic
	_mascaraPIC1(0xFF); // 1111 1000
    _mascaraPIC2(0xFF); // 1110 1111

	_Cli();

	// Inicializo todos los drivers
	inicializarPantalla();
	inicializarTeclado();
	inicializarMouse();

	printf("\n");
	printf("        ****************************************************************\n");
	printf("        *                                                              *\n");
	printf("        *                                                              *\n");
	printf("        *            TPE - ARQUITECTURA DE LAS COMPUTADORAS            *\n");
	printf("        *                                                              *\n");
	printf("        *          DANIEL GOLDBERG - ALEJANDRO PETIT - MARU CURA       *\n");
	printf("        *                                                              *\n");
	printf("        ****************************************************************\n\n\n");

	prompt();

	cargaIDT();
	cargaGDT();

	_Sti();

    while(1)
    {
    }
    return 0;
}

/*
 * Devuelve un puntero al File Descriptor ubicado en el indice indicado por el parametro
 */
FD* open(int fd)
{
	return &fdt[fd];
}

/*
 * System Call que imprime n bytes del buffer en el File Descriptor indicado mediante la INT80
 */
void write(int fd, char *buffer, int size)
{
	int i;
	FD *file;

	file=open(fd);

	for(i=0;i<size;i++)
	{
		file->dir[file->cursorW]=buffer[i];
		if (fd==STDOUT)
			file->dir[file->cursorW+1]=WHITE_TXT;
	}
}

/*
 * Funcion auxiliar para imprimir cada caracter de la funcion write
 */
void writeChar(int fd, char chr)
{
	write(fd,&chr,1);
}

/*
 * System Call que lee n bytes del File Descriptor indicado mediante la INT80
 */
void read(int fd, char *buffer, int size)
{
	int i;
	FD *file;

	file=open(fd);

	for(i=0;i<size;i++)
	{
		buffer[i]=file->dir[file->cursorR];

		if (buffer[i]!=0)
			file->cursorR++;
		else
			return;
	}
}

/*
 * Funcion auxiliar para leer cada caracter de la funcion read
 */
void readChar(int fd, char *chr)
{
	read(fd,chr,1);
}

/*
 * Lee un byte de un puerto
 */
unsigned char inportb(int port)
{
	unsigned char ret;
	asm volatile ("inb %%dx,%%al":"=a"(ret):"d"(port));
	return ret;
}

/*
 * Escribe un byte en un puerto
 */
void outportb(int port,unsigned char value)
{
	asm volatile ("outb %%al,%%dx": :"d"(port),"a"(value));
}
